<?php 
namespace xlx\lib;  
class WeakRef{ 
    public static $obj=[];
    public static $gcc=[];
    public static $fcc=[];
    public static function take($hash){ 
        if(!isset(WeakRef::$obj[$hash])){
            return null;//throw new Exception("Error Processing Request", 1);  
        } 
        return new class($hash) {
            public $__hash ; 
            public function __construct( $hash ){ 
                $this->__hash = $hash;  
                WeakRef::$gcc [$this->__hash]++;

                foreach( debug_backtrace() as $f){
                    $d[] = ($f['file']??'').':'.($f['line']??'').' '.($f['class']??'').($f['type']??'').($f['function']??'');
                }
                WeakRef::$fcc[$this->__hash.':'.WeakRef::$gcc [$this->__hash]] = $d;
            }
            public function __clone(){
                WeakRef::$gcc [$this->__hash]++; 
            }
            public function __destruct(){
                unset(WeakRef::$fcc[$this->__hash.':'.WeakRef::$gcc [$this->__hash]]);
                WeakRef::$gcc [$this->__hash]--; 
                if(0 === WeakRef::$gcc[$this->__hash] ){
                    unset(WeakRef::$gcc[$this->__hash]);
                    unset(WeakRef::$obj[$this->__hash]);
                } 
            }
            public function __call($name,$args){
                return WeakRef::$obj[$this->__hash]->$name(...$args);
            }
            public function __get($name){
                if(substr($name,0,2)=='__'){
                    return $this->name;
                }else{ 
                    return WeakRef::$obj[$this->__hash]->$name;
                }
            }
            public function __set($name,$value){
                if(substr($name,0,2)=='__'){
                    return $this->$name = $value;
                }else{
                    return WeakRef::$obj[$this->__hash]->$name=$value;
                }
            }
            public function __isset($name){
                return isset(WeakRef::$obj[$this->__hash]->$name);
            }

            public function __toString(){
                if(\method_exists(WeakRef::$obj[$this->__hash] ,'__toString')){
                    return WeakRef::$obj[$this->__hash]->__toString(); 
                }else{
                    return (string)WeakRef::$obj[$this->__hash];
                }
            }
            public function __debugInfo(){
                if(!isset(WeakRef::$obj[$this->__hash])){
                    return [];
                } 
                return [
                    "__VALUE__"=>json_encode(WeakRef::$obj[$this->__hash],JSON_PRETTY_PRINT,3),
                    "__OBJ_HASH__"=>$this->__hash, 
                    "__REF_COUNT__"=>(string)WeakRef::$gcc[$this->__hash]
                ]; 
            }
        }; 
    }
    public static function share($obj,$hash=null){
        if(empty($hash)){
            $hash = spl_object_hash($obj);  
        }
        if(isset(WeakRef::$obj[$hash])){
            return self::take($hash);
            //throw new \Exception("Error Processing Request", 1); 
        }else{
            WeakRef::$obj[$hash] = $obj;
            WeakRef::$gcc[$hash] = 0;
        } 
        return self::take($hash);
    }
}

// $c = \xlx\WeakRef::share('a',new class{public $a=1;});
// unset($c);
// $c = \xlx\WeakRef::share('a',new class{public $b=1;});

